package signalprocessing;



import ikelib.PlotColor;
import ikelib.drawTools;
import ikelib.wintime;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedList;

import javax.swing.ButtonGroup;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import java.awt.Component;
import javax.swing.JCheckBoxMenuItem;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JMenu;

/**
 * 軸やラベルを表示するＶｉｅｗ
 * 
 * @author ikechan
 *
 */
public class PlotAxis  extends JPanel {

	protected LinkedList<PlotPane> Parent = new LinkedList<PlotPane>();
	protected PlotColor Col = null;
	private int DraggState = 0;
	private Point DraggStartPoint = new Point();
	private double Center = 0.0;
	private double CenterOffset = 0.0;
	private double Width = 0.0;
	private int WindowWidth = 0;
	private boolean DirectionX=false;
	private boolean initflag = false;
	
	private int DivideNumber = 4;		// DivideNumber+1本の分割線を描く　
	private int DivideSubNumber = 1;	// DivideSubNumber-1本の分割線を描く
	private boolean DrawScale = false;
	private boolean DrawSubScale = false;
	
	/**
	 * 表示するときのフォーマット
	 */
	protected String NumberFormat = new String("%.2e");
	/**
	 * 
	 * @return
	 */
	public String getNumberFormat() {
		return NumberFormat;
	}
	public void setNumberFormat(String numberFormat) {
		NumberFormat = numberFormat;
		repaintAll();
	}
	protected String Title;
	protected boolean TitleDisplay=false;
	
	/**
	 * スケールの分割数、プロット領域内の表示非表示を設定する。
	 * @param maindiv  両端をいれて+1本の分割線を描く　1=両端のみ、2=両端と中央
	 * @param maindisp　プロット領域に線を描画するかどうか
	 * @param subdiv　  メインスケールをいくつに分割するか。1=分割なし、2:中央に１つ分割線
	 * @param subdisp　　プロット領域に線を描画するかどうか
	 */
	public void setAxisDivide(int maindiv,boolean maindisp,int subdiv,boolean subdisp){
		DivideNumber = maindiv;
		DrawScale = maindisp;
		DivideSubNumber = subdiv;
		DrawSubScale=subdisp;
	}
	/**
	 * スケールの分割数、プロット領域内の表示非表示を設定する。
	 * @param maindiv  両端をいれて+1本の分割線を描く　1=両端のみ、2=両端と中央
	 * @param maindisp　プロット領域に線を描画するかどうか
	 */
	public void setAxisDivide(int maindiv,boolean maindisp){
		DivideNumber = maindiv;
		DrawScale = maindisp;
		DivideSubNumber = 1;
		DrawSubScale=false;
	}
	public int getAxisDivide(){
		return DivideNumber;
	}
	public int getAxisDivideSub(){
		return DivideSubNumber;
	}
	public boolean isAxisDivideLineVisible(){
		return DrawScale;
	}
	public boolean isAxisDivideSubLineVisible(){
		return DrawSubScale;
	}
	
	private JCheckBoxMenuItem chkbtnTitle;
	public PlotAxis(){
		
		JPopupMenu popupMenuAxis = new JPopupMenu();
		addPopup(this, popupMenuAxis);
		
		chkbtnTitle = new JCheckBoxMenuItem("Show Title");
		chkbtnTitle.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if(chkbtnTitle.isSelected()){
					String init = "";
					if(Title!=null) init = Title;
					String t = JOptionPane.showInputDialog(null,"Specify the title of axis",(Object)init);
					if(t!= null){
						Title = t;
						TitleDisplay=true;
					}
					
				}
				else{
					TitleDisplay=false;
				}
				repaintAll();
			}
		});
		popupMenuAxis.add(chkbtnTitle);
		
		
		ButtonGroup buttonGroup = new ButtonGroup();
		JMenu mnNewMenu = new JMenu("Format");
		mnNewMenu.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String fmt = getNumberFormat();
				if(fmt.compareTo("1.2e-3")==0){
					rdFormatp1e.setSelected(true);
				}
				else if(fmt.compareTo("1.23e-4")==0){
					rdFormatp2e.setSelected(true);
				}
				else if(fmt.compareTo("1.234e-5")==0){
					rdFormatp3e.setSelected(true);
				}
				else if(fmt.compareTo("123")==0){
					rdFormatf.setSelected(true);
				}
			}
		});
		popupMenuAxis.add(mnNewMenu);
		
		rdFormatp1e = new JRadioButtonMenuItem("1.2e-3");
		rdFormatp1e.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setNumberFormat("%.1e");
			}

		});
		mnNewMenu.add(rdFormatp1e);
		buttonGroup.add(rdFormatp1e);
		
		rdFormatp2e = new JRadioButtonMenuItem("1.23e-4");
		rdFormatp2e.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setNumberFormat("%.2e");
			}
		});
		mnNewMenu.add(rdFormatp2e);
		buttonGroup.add(rdFormatp2e);
		
		rdFormatp3e = new JRadioButtonMenuItem("1.234e-5");
		rdFormatp3e.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setNumberFormat("%.3e");
			}
		});
		mnNewMenu.add(rdFormatp3e);
		buttonGroup.add(rdFormatp3e);

		rdFormatf = new JRadioButtonMenuItem("123");
		rdFormatf.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setNumberFormat("%.0f");
			}
		});
		mnNewMenu.add(rdFormatf);
		buttonGroup.add(rdFormatf);
		
		
		
		
		Parent.clear();
	}

	
	
	public PlotAxis(PlotPane p){
		addParent(p);

	}
	public void clearParent(){
		Parent.clear();
	}
	public void setParent(PlotPane p){
		addParent(p);
		init();
	}
	private void addParent(PlotPane p){
		for(int i=0;i<Parent.size();i++){
			if(Parent.get(i) == (p)){
				return;
			}
		}
		Parent.add(p);
	}
	public void removeParentAll(){
		Parent = new LinkedList<PlotPane>();
	}
	public boolean removeParent(PlotPane p){
		for(int i=0;i<Parent.size();i++){
			if(Parent.get(i) == (p)){
				Parent.remove(i);
				return true;
			}
		}
		return false;
	}
	/**
	 *  初期化
	 */
	private void init() {
		if(initflag) return;
		initflag = true;
		// マウスリスナーを登録
		addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent arg0) {
				if(DraggState ==0){
					DraggState=1;
					DraggStartPoint = arg0.getPoint();//ドラッグを開始した座標を保存
					//System.out.println("DraggStart"+DraggStartPoint);
					if(Parent.size()>=1){
						PlotPane p=Parent.get(0);
						p.onAxisDragEnter();
						if(!DirectionX){
							Center = p.getYScaleCenter();
							Width = p.getYScaleSpan();
							CenterOffset=0.0;
							WindowWidth = getSize().height;
						}
						else{
							Center = p.getXScaleCenter();
							Width = p.getXScaleSpan();
							CenterOffset=0.0;
							WindowWidth = getSize().width;
						}
						
					}
					
					if(Parent!=null){
					}
			}
			}
			public void mouseReleased(MouseEvent arg0) {
				if(DraggState>0){
					DraggState=0;
				//	System.out.println("DraggEnd");
//					if(Parent!=null){
//						Parent.onAxisDragEnd();
//					}
				}
			}
			
		});
		// マウスモーションリスナーを登録
		addMouseMotionListener(new MouseAdapter() {
			public void mouseDragged(MouseEvent arg0) {
				if(DraggState == 1){
					Point pt = arg0.getPoint();
					int dc =0;
					if(Parent.size()>=1){
						for(int idx = 0;idx<Parent.size();idx++){
							PlotPane p=Parent.get(idx);
							p.onAxisDragging(CenterOffset);
							if(!DirectionX){
								dc =-DraggStartPoint.y + pt.y;
								CenterOffset = Width * (double)dc / (WindowWidth);
								p.setYScaleCenter(Center + CenterOffset);
							}
							else{
								dc =-DraggStartPoint.x + pt.x;
								CenterOffset = Width * (double)dc / (WindowWidth);
								p.setXScaleCenter(Center - CenterOffset);
							}
						}
					}
				}
			}
		});
		
	}
	/**
	 * Ｙスケール最大値を返す
	 * @return
	 */
	protected double getYScaleMax(){
		//if(Parent!=null) return Parent.getYScaleMax();
		if(Parent.size()>=1){
			PlotPane p=Parent.get(0);
			return p.getYScaleMax();
		}		
		
		return 10.0;
	}
	/**
	 * Ｙスケール最小値を返す
	 * @return
	 */
	protected double getYScaleMin(){
		//if(Parent!=null) return Parent.getYScaleMin();
		if(Parent.size()>=1){
			PlotPane p=Parent.get(0);
			return p.getYScaleMin();
		}		
		return 10.0;
	}
	/**
	 * Xスケール最大値を返す
	 * @return
	 */
	protected double getXScaleMax(){
		//if(Parent!=null) return Parent.getYScaleMax();
		if(Parent.size()>=1){
			PlotPane p=Parent.get(0);
			return p.getXScaleMax();
		}		
		
		return 10.0;
	}
	/**
	 * Xスケール最小値を返す
	 * @return
	 */
	protected double getXScaleMin(){
		//if(Parent!=null) return Parent.getYScaleMin();
		if(Parent.size()>=1){
			PlotPane p=Parent.get(0);
			return p.getXScaleMin();
		}		
		return 10.0;
	}
	/**
	 * 軸の方向　x,y をセットする
	 * @param x
	 */
	public void setDirection(boolean x){
		DirectionX=x;
	}
	
	public void setXScaleMaxMin(double max,double min){
		for(int i=0;i<Parent.size();i++){
			PlotPane p=Parent.get(i);
			p.setXScaleMaxMin(max,min);
		}
//		if(Parent.size()>=1){
//			PlotPane p=Parent.get(0);
//			return p.getXScaleMin();
//		}		
		
	}
	
	/*
	 * 軸をどちら側がに書くかのフラグ
	 */
	public static final int AxisPlacedTop = 0;
	public static final int AxisPlacedRight = 1;
	public static final int AxisPlacedBottom = 2;
	public static final int AxisPlacedLeft = 3;
	
	/**
	 * 目盛線の破線
	 */
	float dash[] = { 3.0f,3.0f };
	private BasicStroke StrokeDots = new BasicStroke(1.0f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0f,dash,0.0f  );
	
	/**
	 * プロット内部に目盛を書く
	 * @param g　グラフィックコンテキスト
	 * @param pos　軸の場所（方向）AxisPlacedTop、AxisPlacedBottom　上下に書く、AxisPlacedRight、AxisPlacedLeft 左右に書く
	 * @param r
	 * @param divide
	 * @return
	 */
	protected void drawScale(Graphics2D g, int pos,Rectangle r){
		drawScale(g,pos,r,DivideNumber);
	}
	protected void drawScale(Graphics2D g, int pos,Rectangle r,int divide){
		
		if(!DrawScale) return;
		int x1 = r.x;
		int x2 = r.x + r.width-1;
		int y1 = r.y;
		int y2 = r.y + r.height-1;
		
		if(Col!=null){
			g.setColor(Col.ColorAxis);
			g.setBackground(Col.ColorBackGround);
		}
		double interval=0.0;
		
		Stroke strk = g.getStroke();
		g.setStroke(StrokeDots);
		
		switch(pos){
		case AxisPlacedTop: // top |______|_______|
		case AxisPlacedBottom: // bottom  
			interval = (double)(r.width)/(divide);
			for(int i=0;i<divide+1;i++){
				int x = (int)(x1 + i*interval);
				if(i==divide) x--;
				g.drawLine(x,y1,x,y2);
				if(DrawSubScale){
					if(i!=0){
						for(int j=1;j<DivideSubNumber;j++){
							g.drawLine((int)(x-j*interval/DivideSubNumber), y1, (int)(x-j*interval/DivideSubNumber), y2);
						}
					}
				}
			}
			break;
		case AxisPlacedRight: // draw left side 
		case AxisPlacedLeft: // draw right size
			interval = (double)(r.height)/(divide);
			for(int i=0;i<divide+1;i++){
				int y = (int)(y1 + i*interval);
				if(i==divide) y--;
				g.drawLine(x1,y,x2,y);
				if(DrawSubScale){
					if(i!=0){
						for(int j=1;j<DivideSubNumber;j++){
							g.drawLine(x1, (int)(y-j*interval/DivideSubNumber), x2, (int)(y-j*interval/DivideSubNumber));
						}
					}
				}
			}
			break;
			
		}
		g.setStroke(strk);
		return;
	}

	
	/**
	 * 軸線の太線
	 */
	private BasicStroke StrokeBold = new BasicStroke(3.0f);
	private JRadioButtonMenuItem rdFormatp1e;
	private JRadioButtonMenuItem rdFormatp2e;
	private JRadioButtonMenuItem rdFormatp3e;
	private JRadioButtonMenuItem rdFormatf;

	/**
	 * 軸を書く　
	 * @param g：　Graphics2D 描画したいGraphics2Dオブジェクト
	 * @param pos　int 0: 上部に配置（つまり、rの下部に軸を書き上に向かって目盛線が描画される） ,1:右に配置 （左に寄せて目盛線）、以下右回りに、、
	 * @param r: rectangle 描画したい領域
	 * @param divide int 0: メモリなし、1: 左、または上に１つ、２：　左右、または上下に１つずつみたいな、、
	 */
	protected Point[] drawAxis(Graphics2D g, int pos,Rectangle r){
		return drawAxis(g,pos,r,DivideNumber);
	}
	protected Point[] drawAxis(Graphics2D g, int pos,Rectangle r,int divide){
		int x1 = r.x;
		int x2 = r.x + r.width-1;
		int y1 = r.y;
		int y2 = r.y + r.height-1;
		Point[] ret = new Point[divide+1];
		
		if(Col!=null){
			g.setColor(Col.ColorAxis);
			g.setBackground(Col.ColorBackGround);
		}
		double interval=0.0;
		Stroke stkold;
		switch(pos){
		case AxisPlacedTop: // top |______|_______|
			stkold = g.getStroke();
			g.setStroke(StrokeBold);
			g.drawLine(x1,y2,x2,y2);
			g.setStroke(stkold);
			interval = (double)(r.width)/(divide);
			for(int i=0;i<divide+1;i++){
				int x = (int)(x1 + i*interval);
				if(i==divide) x--;
				g.drawLine(x,y1,x,y2);
				ret[i] = new Point(x,y1);
				if(i!=0){
					for(int j=1;j<DivideSubNumber;j++){
						g.drawLine((int)(x-j*interval/DivideSubNumber), (y1+y2)/2, (int)(x-j*interval/DivideSubNumber), y2);
					}
				}
			}
			break;
		case AxisPlacedRight: // draw left side 
			stkold = g.getStroke();
			g.setStroke(StrokeBold);
			g.drawLine(x1,y1,x1,y2);
			g.setStroke(stkold);
			interval = (double)(r.height)/(divide);
			for(int i=0;i<divide+1;i++){
				int y = (int)(y1 + i*interval);
				if(i==divide) y--;
				g.drawLine(x1,y,x2,y);
				ret[i] = new Point(x2,y);
				if(i!=0){
					for(int j=1;j<DivideSubNumber;j++){
						g.drawLine(x1, (int)(y-j*interval/DivideSubNumber), (x2+x1)/2, (int)(y-j*interval/DivideSubNumber));
					}
				}
			}
			break;
		case AxisPlacedBottom: // bottom  
			stkold = g.getStroke();
			g.setStroke(StrokeBold);
			g.drawLine(x1,y1,x2,y1);
			g.setStroke(stkold);
			interval = (double)(r.width)/(divide);
			for(int i=0;i<divide+1;i++){
				int x = (int)(x1 + i*interval);
				if(i==divide) x--;
				g.drawLine(x,y1,x,y2);
				ret[i] = new Point(x,y2);
				if(i!=0){
					for(int j=1;j<DivideSubNumber;j++){
						g.drawLine((int)(x-j*interval/DivideSubNumber), y1, (int)(x-j*interval/DivideSubNumber), (y1+y2)/2);
					}
				}
			}
			break;
		case AxisPlacedLeft: // draw right size
			stkold = g.getStroke();
			g.setStroke(StrokeBold);
			g.drawLine(x2,y1,x2,y2);
			g.setStroke(stkold);
			interval = (double)(r.height)/(divide);
			for(int i=0;i<divide+1;i++){
				int y = (int)(y1 + i*interval);
				if(i==divide) y--;
				g.drawLine(x1,y,x2,y);
				ret[i] = new Point(x1,y);
				if(i!=0){
					for(int j=1;j<DivideSubNumber;j++){
						g.drawLine((x1+x2)/2, (int)(y-j*interval/DivideSubNumber), x2, (int)(y-j*interval/DivideSubNumber));
					}
				}
			}
			break;
			
		}
		return ret;
	}
	/**
	 * ラベル付きの目盛を書く
	 * @param g
	 * @param pos
	 * @param r
	 * @param divide
	 * @param label
	 */
	protected  void drawAxis(Graphics2D g, int pos,Rectangle r,int divide,String[] label){
		Point[] p = drawAxis(g,pos,r,divide);
		for(int i=0;i<label.length;i++){
			int x,y,position;
			x = p[i].x;
			y = p[i].y;
			position =0;
			switch(pos){
			case AxisPlacedTop:
				position = drawTools.POSITION_LEFT_BOTTOM;
				if(i==p.length-1){
					position = drawTools.POSITION_RIGHT_BOTTOM;
				}
				break;
			case AxisPlacedRight: 
				position = drawTools.POSITION_LEFT_CENTER;
				if(i==0){
					position = drawTools.POSITION_LEFT_TOP;
				}
				else if(i==p.length-1){
					position = drawTools.POSITION_LEFT_BOTTOM;
				}
				break;
			case AxisPlacedBottom: 
				position = drawTools.POSITION_LEFT_TOP;
				if(i==p.length-1){
					position = drawTools.POSITION_RIGHT_TOP;
				}
				break;
			case AxisPlacedLeft: 
			default:
				position = drawTools.POSITION_RIGHT_CENTER;
				if(i==0){
					position = drawTools.POSITION_RIGHT_TOP;
				}
				else if(i==p.length-1){
					position = drawTools.POSITION_RIGHT_BOTTOM;
				}
				
				break;
			
			}
			if(Col!=null) g.setColor(Col.ColorAxisText);
			drawTools.drawText(g, label[i], x, y, position);
		}
	}
	@Override
	public void paintComponent(Graphics g){
		//System.out.println("test");
		 //super.paintComponent(g);   
	}
	/**
	 * すべてを再描画する
	 */
	public void repaintAll(){
		Rectangle r = new Rectangle(0,0,getWidth(),getHeight());
		repaint(r);
	}
	
	private static void addPopup(Component component, final JPopupMenu popup) {
		component.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}
			public void mouseReleased(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}
			private void showMenu(MouseEvent e) {
				popup.show(e.getComponent(), e.getX(), e.getY());
			}
		});
	}
}
